home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / scripts / basic / docproc.c < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  11.2 KB  |  449 lines

  1. /*
  2.  *    docproc is a simple preprocessor for the template files
  3.  *      used as placeholders for the kernel internal documentation.
  4.  *    docproc is used for documentation-frontend and
  5.  *      dependency-generator.
  6.  *    The two usages have in common that they require
  7.  *    some knowledge of the .tmpl syntax, therefore they
  8.  *    are kept together.
  9.  *
  10.  *    documentation-frontend
  11.  *        Scans the template file and call kernel-doc for
  12.  *        all occurrences of ![EIF]file
  13.  *        Beforehand each referenced file is scanned for
  14.  *        any symbols that are exported via these macros:
  15.  *            EXPORT_SYMBOL(), EXPORT_SYMBOL_GPL(), &
  16.  *            EXPORT_SYMBOL_GPL_FUTURE()
  17.  *        This is used to create proper -function and
  18.  *        -nofunction arguments in calls to kernel-doc.
  19.  *        Usage: docproc doc file.tmpl
  20.  *
  21.  *    dependency-generator:
  22.  *        Scans the template file and list all files
  23.  *        referenced in a format recognized by make.
  24.  *        Usage:    docproc depend file.tmpl
  25.  *        Writes dependency information to stdout
  26.  *        in the following format:
  27.  *        file.tmpl src.c    src2.c
  28.  *        The filenames are obtained from the following constructs:
  29.  *        !Efilename
  30.  *        !Ifilename
  31.  *        !Dfilename
  32.  *        !Ffilename
  33.  *        !Pfilename
  34.  *
  35.  */
  36.  
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include <unistd.h>
  42. #include <limits.h>
  43. #include <sys/types.h>
  44. #include <sys/wait.h>
  45.  
  46. /* exitstatus is used to keep track of any failing calls to kernel-doc,
  47.  * but execution continues. */
  48. int exitstatus = 0;
  49.  
  50. typedef void DFL(char *);
  51. DFL *defaultline;
  52.  
  53. typedef void FILEONLY(char * file);
  54. FILEONLY *internalfunctions;
  55. FILEONLY *externalfunctions;
  56. FILEONLY *symbolsonly;
  57.  
  58. typedef void FILELINE(char * file, char * line);
  59. FILELINE * singlefunctions;
  60. FILELINE * entity_system;
  61. FILELINE * docsection;
  62.  
  63. #define MAXLINESZ     2048
  64. #define MAXFILES      250
  65. #define KERNELDOCPATH "scripts/"
  66. #define KERNELDOC     "kernel-doc"
  67. #define DOCBOOK       "-docbook"
  68. #define FUNCTION      "-function"
  69. #define NOFUNCTION    "-nofunction"
  70. #define NODOCSECTIONS "-no-doc-sections"
  71.  
  72. char *srctree;
  73.  
  74. void usage (void)
  75. {
  76.     fprintf(stderr, "Usage: docproc {doc|depend} file\n");
  77.     fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
  78.     fprintf(stderr, "doc: frontend when generating kernel documentation\n");
  79.     fprintf(stderr, "depend: generate list of files referenced within file\n");
  80.     fprintf(stderr, "Environment variable SRCTREE: absolute path to kernel source tree.\n");
  81. }
  82.  
  83. /*
  84.  * Execute kernel-doc with parameters given in svec
  85.  */
  86. void exec_kernel_doc(char **svec)
  87. {
  88.     pid_t pid;
  89.     int ret;
  90.     char real_filename[PATH_MAX + 1];
  91.     /* Make sure output generated so far are flushed */
  92.     fflush(stdout);
  93.     switch (pid=fork()) {
  94.         case -1:
  95.             perror("fork");
  96.             exit(1);
  97.         case  0:
  98.             memset(real_filename, 0, sizeof(real_filename));
  99.             strncat(real_filename, srctree, PATH_MAX);
  100.             strncat(real_filename, KERNELDOCPATH KERNELDOC,
  101.                     PATH_MAX - strlen(real_filename));
  102.             execvp(real_filename, svec);
  103.             fprintf(stderr, "exec ");
  104.             perror(real_filename);
  105.             exit(1);
  106.         default:
  107.             waitpid(pid, &ret ,0);
  108.     }
  109.     if (WIFEXITED(ret))
  110.         exitstatus |= WEXITSTATUS(ret);
  111.     else
  112.         exitstatus = 0xff;
  113. }
  114.  
  115. /* Types used to create list of all exported symbols in a number of files */
  116. struct symbols
  117. {
  118.     char *name;
  119. };
  120.  
  121. struct symfile
  122. {
  123.     char *filename;
  124.     struct symbols *symbollist;
  125.     int symbolcnt;
  126. };
  127.  
  128. struct symfile symfilelist[MAXFILES];
  129. int symfilecnt = 0;
  130.  
  131. void add_new_symbol(struct symfile *sym, char * symname)
  132. {
  133.     sym->symbollist =
  134.           realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
  135.     sym->symbollist[sym->symbolcnt++].name = strdup(symname);
  136. }
  137.  
  138. /* Add a filename to the list */
  139. struct symfile * add_new_file(char * filename)
  140. {
  141.     symfilelist[symfilecnt++].filename = strdup(filename);
  142.     return &symfilelist[symfilecnt - 1];
  143. }
  144.  
  145. /* Check if file already are present in the list */
  146. struct symfile * filename_exist(char * filename)
  147. {
  148.     int i;
  149.     for (i=0; i < symfilecnt; i++)
  150.         if (strcmp(symfilelist[i].filename, filename) == 0)
  151.             return &symfilelist[i];
  152.     return NULL;
  153. }
  154.  
  155. /*
  156.  * List all files referenced within the template file.
  157.  * Files are separated by tabs.
  158.  */
  159. void adddep(char * file)           { printf("\t%s", file); }
  160. void adddep2(char * file, char * line)     { line = line; adddep(file); }
  161. void noaction(char * line)           { line = line; }
  162. void noaction2(char * file, char * line)   { file = file; line = line; }
  163.  
  164. /* Echo the line without further action */
  165. void printline(char * line)               { printf("%s", line); }
  166.  
  167. /*
  168.  * Find all symbols in filename that are exported with EXPORT_SYMBOL &
  169.  * EXPORT_SYMBOL_GPL (& EXPORT_SYMBOL_GPL_FUTURE implicitly).
  170.  * All symbols located are stored in symfilelist.
  171.  */
  172. void find_export_symbols(char * filename)
  173. {
  174.     FILE * fp;
  175.     struct symfile *sym;
  176.     char line[MAXLINESZ];
  177.     if (filename_exist(filename) == NULL) {
  178.         char real_filename[PATH_MAX + 1];
  179.         memset(real_filename, 0, sizeof(real_filename));
  180.         strncat(real_filename, srctree, PATH_MAX);
  181.         strncat(real_filename, filename,
  182.                 PATH_MAX - strlen(real_filename));
  183.         sym = add_new_file(filename);
  184.         fp = fopen(real_filename, "r");
  185.         if (fp == NULL)
  186.         {
  187.             fprintf(stderr, "docproc: ");
  188.             perror(real_filename);
  189.             exit(1);
  190.         }
  191.         while (fgets(line, MAXLINESZ, fp)) {
  192.             char *p;
  193.             char *e;
  194.             if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) ||
  195.                             ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) {
  196.                 /* Skip EXPORT_SYMBOL{_GPL} */
  197.                 while (isalnum(*p) || *p == '_')
  198.                     p++;
  199.                 /* Remove parentheses & additional whitespace */
  200.                 while (isspace(*p))
  201.                     p++;
  202.                 if (*p != '(')
  203.                     continue; /* Syntax error? */
  204.                 else
  205.                     p++;
  206.                 while (isspace(*p))
  207.                     p++;
  208.                 e = p;
  209.                 while (isalnum(*e) || *e == '_')
  210.                     e++;
  211.                 *e = '\0';
  212.                 add_new_symbol(sym, p);
  213.             }
  214.         }
  215.         fclose(fp);
  216.     }
  217. }
  218.  
  219. /*
  220.  * Document all external or internal functions in a file.
  221.  * Call kernel-doc with following parameters:
  222.  * kernel-doc -docbook -nofunction function_name1 filename
  223.  * Function names are obtained from all the src files
  224.  * by find_export_symbols.
  225.  * intfunc uses -nofunction
  226.  * extfunc uses -function
  227.  */
  228. void docfunctions(char * filename, char * type)
  229. {
  230.     int i,j;
  231.     int symcnt = 0;
  232.     int idx = 0;
  233.     char **vec;
  234.  
  235.     for (i=0; i <= symfilecnt; i++)
  236.         symcnt += symfilelist[i].symbolcnt;
  237.     vec = malloc((2 + 2 * symcnt + 3) * sizeof(char *));
  238.     if (vec == NULL) {
  239.         perror("docproc: ");
  240.         exit(1);
  241.     }
  242.     vec[idx++] = KERNELDOC;
  243.     vec[idx++] = DOCBOOK;
  244.     vec[idx++] = NODOCSECTIONS;
  245.     for (i=0; i < symfilecnt; i++) {
  246.         struct symfile * sym = &symfilelist[i];
  247.         for (j=0; j < sym->symbolcnt; j++) {
  248.             vec[idx++]     = type;
  249.             vec[idx++] = sym->symbollist[j].name;
  250.         }
  251.     }
  252.     vec[idx++]     = filename;
  253.     vec[idx] = NULL;
  254.     printf("<!-- %s -->\n", filename);
  255.     exec_kernel_doc(vec);
  256.     fflush(stdout);
  257.     free(vec);
  258. }
  259. void intfunc(char * filename) {    docfunctions(filename, NOFUNCTION); }
  260. void extfunc(char * filename) { docfunctions(filename, FUNCTION);   }
  261.  
  262. /*
  263.  * Document specific function(s) in a file.
  264.  * Call kernel-doc with the following parameters:
  265.  * kernel-doc -docbook -function function1 [-function function2]
  266.  */
  267. void singfunc(char * filename, char * line)
  268. {
  269.     char *vec[200]; /* Enough for specific functions */
  270.         int i, idx = 0;
  271.         int startofsym = 1;
  272.     vec[idx++] = KERNELDOC;
  273.     vec[idx++] = DOCBOOK;
  274.  
  275.         /* Split line up in individual parameters preceded by FUNCTION */
  276.         for (i=0; line[i]; i++) {
  277.                 if (isspace(line[i])) {
  278.                         line[i] = '\0';
  279.                         startofsym = 1;
  280.                         continue;
  281.                 }
  282.                 if (startofsym) {
  283.                         startofsym = 0;
  284.                         vec[idx++] = FUNCTION;
  285.                         vec[idx++] = &line[i];
  286.                 }
  287.         }
  288.     vec[idx++] = filename;
  289.     vec[idx] = NULL;
  290.     exec_kernel_doc(vec);
  291. }
  292.  
  293. /*
  294.  * Insert specific documentation section from a file.
  295.  * Call kernel-doc with the following parameters:
  296.  * kernel-doc -docbook -function "doc section" filename
  297.  */
  298. void docsect(char *filename, char *line)
  299. {
  300.     char *vec[6]; /* kerneldoc -docbook -function "section" file NULL */
  301.     char *s;
  302.  
  303.     for (s = line; *s; s++)
  304.         if (*s == '\n')
  305.             *s = '\0';
  306.  
  307.     vec[0] = KERNELDOC;
  308.     vec[1] = DOCBOOK;
  309.     vec[2] = FUNCTION;
  310.     vec[3] = line;
  311.     vec[4] = filename;
  312.     vec[5] = NULL;
  313.     exec_kernel_doc(vec);
  314. }
  315.  
  316. /*
  317.  * Parse file, calling action specific functions for:
  318.  * 1) Lines containing !E
  319.  * 2) Lines containing !I
  320.  * 3) Lines containing !D
  321.  * 4) Lines containing !F
  322.  * 5) Lines containing !P
  323.  * 6) Default lines - lines not matching the above
  324.  */
  325. void parse_file(FILE *infile)
  326. {
  327.     char line[MAXLINESZ];
  328.     char * s;
  329.     while (fgets(line, MAXLINESZ, infile)) {
  330.         if (line[0] == '!') {
  331.             s = line + 2;
  332.             switch (line[1]) {
  333.                 case 'E':
  334.                     while (*s && !isspace(*s)) s++;
  335.                     *s = '\0';
  336.                     externalfunctions(line+2);
  337.                     break;
  338.                 case 'I':
  339.                     while (*s && !isspace(*s)) s++;
  340.                     *s = '\0';
  341.                     internalfunctions(line+2);
  342.                     break;
  343.                 case 'D':
  344.                     while (*s && !isspace(*s)) s++;
  345.                                         *s = '\0';
  346.                                         symbolsonly(line+2);
  347.                                         break;
  348.                 case 'F':
  349.                     /* filename */
  350.                     while (*s && !isspace(*s)) s++;
  351.                     *s++ = '\0';
  352.                                         /* function names */
  353.                     while (isspace(*s))
  354.                         s++;
  355.                     singlefunctions(line +2, s);
  356.                     break;
  357.                 case 'P':
  358.                     /* filename */
  359.                     while (*s && !isspace(*s)) s++;
  360.                     *s++ = '\0';
  361.                     /* DOC: section name */
  362.                     while (isspace(*s))
  363.                         s++;
  364.                     docsection(line + 2, s);
  365.                     break;
  366.                 default:
  367.                     defaultline(line);
  368.             }
  369.         }
  370.         else {
  371.             defaultline(line);
  372.         }
  373.     }
  374.     fflush(stdout);
  375. }
  376.  
  377.  
  378. int main(int argc, char *argv[])
  379. {
  380.     FILE * infile;
  381.  
  382.     srctree = getenv("SRCTREE");
  383.     if (!srctree)
  384.         srctree = getcwd(NULL, 0);
  385.     if (argc != 3) {
  386.         usage();
  387.         exit(1);
  388.     }
  389.     /* Open file, exit on error */
  390.     infile = fopen(argv[2], "r");
  391.         if (infile == NULL) {
  392.                 fprintf(stderr, "docproc: ");
  393.                 perror(argv[2]);
  394.                 exit(2);
  395.         }
  396.  
  397.     if (strcmp("doc", argv[1]) == 0)
  398.     {
  399.         /* Need to do this in two passes.
  400.          * First pass is used to collect all symbols exported
  401.          * in the various files;
  402.          * Second pass generate the documentation.
  403.          * This is required because some functions are declared
  404.          * and exported in different files :-((
  405.          */
  406.         /* Collect symbols */
  407.         defaultline       = noaction;
  408.         internalfunctions = find_export_symbols;
  409.         externalfunctions = find_export_symbols;
  410.         symbolsonly       = find_export_symbols;
  411.         singlefunctions   = noaction2;
  412.         docsection        = noaction2;
  413.         parse_file(infile);
  414.  
  415.         /* Rewind to start from beginning of file again */
  416.         fseek(infile, 0, SEEK_SET);
  417.         defaultline       = printline;
  418.         internalfunctions = intfunc;
  419.         externalfunctions = extfunc;
  420.         symbolsonly       = printline;
  421.         singlefunctions   = singfunc;
  422.         docsection        = docsect;
  423.  
  424.         parse_file(infile);
  425.     }
  426.     else if (strcmp("depend", argv[1]) == 0)
  427.     {
  428.         /* Create first part of dependency chain
  429.          * file.tmpl */
  430.         printf("%s\t", argv[2]);
  431.         defaultline       = noaction;
  432.         internalfunctions = adddep;
  433.         externalfunctions = adddep;
  434.         symbolsonly       = adddep;
  435.         singlefunctions   = adddep2;
  436.         docsection        = adddep2;
  437.         parse_file(infile);
  438.         printf("\n");
  439.     }
  440.     else
  441.     {
  442.         fprintf(stderr, "Unknown option: %s\n", argv[1]);
  443.         exit(1);
  444.     }
  445.     fclose(infile);
  446.     fflush(stdout);
  447.     return exitstatus;
  448. }
  449.